package com.itttq.gshop.generic.util;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.codec.binary.Base64;

/**
 * 系统静态变量类
 *
 * @createTime: 2014-11-25 上午9:44:34
 * @author: <a href="mailto:gaoxvguo060@haopinfeng.com">高绪国</a>
 * @version: 0.1
 * @changesSum:
 * 
 */
public class Constants {
	/** 状态：开启，值为1 */
	public static final int STATUTS_OPEN = 1;
	/** 状态：关闭，值为2 */
	public static final int STATUTS_CLOSE = 2;
	/** 逗号分隔符：, */
	public static final String SEPARATOR_COMMA = ",";
	/** 反斜杠分隔符：/ */
	public static final String SEPARATOR_BACKSLASH = "/";
	/** 点分隔符：. */
	public static final String SEPARATOR_SPOT = ".";

	/** WEB项目使用 */
	/* 图像验证码 */
	public static final String SESSION_CODE_IMG = "img_code";
	/* 注册验证码 */
	public static final String SESSION_CODE_REG = "reg_code";
	/* 找回密码验证码 */
	public static final String SESSION_CODE_GETPWD = "getpwd_code";

	/** SESSION中保留的系统购物车对象KEY值，值为cart */
	public static final String SESSION_CART = "cart";
	/** SESSION中保留的系统用戶對象KEY值，值为user */
	public static final String SESSION_USER = "user";
	/** SESSION中保留的系统上一次的URL，值为last_url */
	public static final String SESSION_URL_LAST = "last_url";
	public static List<String> IMG_TYPES = new ArrayList<String>();
	
	/** 积分变化，增加积分 */
	public static final String SCORE_CHANGE_ADD = "+";
	/** 积分变化，减少积分 */
	public static final String SCORE_CHANGE_DEDUCT = "-";

	/** 积分兑换比例设置编码 */
	public static final String SCORE_EXCH_RATE = "score_exchange_rate";
	/** 会员购买获得积分比率 */
	public static final String SCORE_GIVE_RATE = "score_give_rate";
	/** 会员购买后推广者获得积分比率 */
	public static final String SCORE_PROMOTE_RATE = "score_promote_rate";
	/** 会员注册后推广者获得积分数（0 ~ 10000） */
	public static final String SCORE_MEMBER_REG_PROMOTE = "score_member_reg_promote";
	/** 会员注册获得的积分数（0 ~ 10000） */
	public static final String SCORE_MEMBER_REG = "score_member_reg";
	/** 赠送积分的最大值，防止误操作 */
	public static final String SCORE_GIVE_MAX = "score_give_max";
	
	/** 用户类型：普通用户，值为1 */
	public static final int TYPE_USER_MEMBER = 1;
	/** 用户类型：酒坊大使，值为2 */
	public static final int TYPE_USER_AMBASSADOR = 2;
	
	/** 库存操作：减库存 */
	public static final String OP_INVENTORY_REDUCT = "deduct";
	/** 库存操作：加库存 */
	public static final String OP_INVENTORY_ADD = "return";
	
	/** 上传文件目录：1、广告 - ad；2、产品 - prod；3、帮助 - help；4、分类 - cat；5、用户 - user；9、其他 - other */
	public static Map<Integer, String> UPLOAD_DIR = new HashMap<Integer, String>();
	static {
		IMG_TYPES.add(".jpg");
		IMG_TYPES.add(".png");
		IMG_TYPES.add(".gif");
		IMG_TYPES.add(".jpeg");
		UPLOAD_DIR.put(1, "ad");
		UPLOAD_DIR.put(2, "prod");
		UPLOAD_DIR.put(3, "help");
		UPLOAD_DIR.put(4, "cat");
		UPLOAD_DIR.put(5, "user");
		UPLOAD_DIR.put(9, "other");
	}

	/**
	 * 楼层模板类型：1、热卖商品；2、新品；3、每行两张图；4、左大图、右小图显示；5、左小图、右大图显示。
	 */
	public static enum FloorTmpl {
		/** 热卖商品，值为1 */
		HOT("热卖", 1), /** 新品，值为2 */
		NEW("新品", 2), /** 每行两张图，值为3 */
		TWO_IMGS("两张每行", 3),
		/** 三张图-左大右小，值为4 */
		THREE_BIG_SMALL("左大右小", 4), /** 三张图-右大左小，值为5 */
		THREE_SMALL_BIG("右大左小", 5);
		private String text;
		private int val;

		private FloorTmpl(String text, int val) {
			this.text = text;
			this.val = val;
		}

		public String getText() {
			return text;
		}

		public int getVal() {
			return this.val;
		}
	}
	
	/**
	 * 积分变化编码：reg、注册；promote、推广；promote、购买商品；sys、系统赠送。
	 */
	public static enum ScoreChangeCode {
		/** 注册，值为1 */
		REG("reg", "注册赠送"), /** 推广获得，值为reg */
		REG_PROMOTE("promote", "推广注册"), /** 推广注册，值为promote */
		PROMOTE("promote", "推广购物"), /** 推广购物，值为promote */
		BUY("buy", "购物获得"), /** 购物，值为promote */
		/** 系统赠送，值为4 */
		sys("sys", "系统赠送");
		private String text;
		private String val;

		private ScoreChangeCode(String text, String val) {
			this.text = text;this.val = val;
		}
		public String getText() {
			return text;
		}
		public String getVal() {
			return this.val;
		}
	}
	/**
	 * 广告类型：1、幻灯广告；2、幻灯片下面广告；3、楼层广告；4、列表页广告。
	 */
	public static enum AdCategory {
		/** 幻灯广告，值为1 */
		SLIDE("幻灯", 1), /** 幻灯片下面或右边广告，值为2 */
		SLIDE_UNDER("首页", 2), /** 楼层广告，值为3 */
		FLOOR("楼层", 3),
		/** 列表页广告，值为4 */
		LIST("列表", 4);
		private String text;
		private int val;

		private AdCategory(String text, int val) {
			this.text = text;
			this.val = val;
		}

		public String getText() {
			return text;
		}

		public int getVal() {
			return this.val;
		}
	}

	/**
	 * 支付状态：1:待付款；2:支付成功；3支付失败；4、支付取消（再次发起支付时，取消之前的支付，保留）
	 */
	public static enum PayStatus {
		/** 待付款，值为1 */
		UNPAY("待付款", 1), /** 支付成功，值为2 */
		SUCCESS("支付成功", 2), /** 支付失败，值为3 */
		FAIL("支付失败", 3),
		/** 支付取消，值为4 */
		CANCEL("支付取消", 4);
		private String text;
		private int val;

		private PayStatus(String text, int val) {
			this.text = text;
			this.val = val;
		}

		public String getText() {
			return text;
		}

		public int getVal() {
			return this.val;
		}
	}


	/**
	 * 支付类型：1:线下；2:支付宝；3微信.
	 */
	public static enum PayMethod {
		/** 线下支付，值为1 */
		OFFLINE("线下支付", 1), /** 支付宝支付，值为2 */
		ALIPAY("支付成功", 2), /** 支付失败，值为3 */
		WXPAY("微信支付", 3);
		private String text; private int val;
		private PayMethod(String text, int val) {
			this.text = text; this.val = val;
		}
		public String getText() {return text;}
		public int getVal() {return this.val;}
	}

	/**
	 * 订单和用户等来源
	 */
	public static enum Source {
		/** PC，值为1 */
		PC("PC端", 1), /** 安卓，值为2 */
		ANDROID("安卓", 2), /** IOS，值为4 */
		IOS("IOS", 4),
		/** H5，值为5 */
		H5("H5", 5),
		/** 微信，值为3 */
		WEBCHAT("微信", 3);
		private String text;
		private int val;

		private Source(String text, int val) {
			this.text = text;
			this.val = val;
		}

		public String getText() {
			return text;
		}

		public int getVal() {
			return this.val;
		}
	}

	/** 商品状态 */
	public static enum WareStatus {
		/** 草稿，值为1 */
		DRAFT("草稿", 1), /** 未上架，值为2 */
		OFFSHELF("未上架", 2),
		/** 上架，值为3 */
		ONSHELF("上架", 3), /** 已删除，值为4 */
		DEL("已删除", 4);
		private String text;
		private int val;

		private WareStatus(String text, int val) {
			this.text = text;
			this.val = val;
		}

		public String getText() {
			return text;
		}

		public int getVal() {
			return this.val;
		}
	}

	/** 发票类型 */
	public static enum InvoiceType {
		/** 增值税发票，值为1 */
		VAT("增值税发票", 1), /** 个人，值为2 */
		PERSONAL("个人", 2),
		/** 普票，值为3 */
		PLAIN("普票", 3), /** 电子发票，值为4 */
		ELECTRONIC("电子发票", 4);
		private String text;
		private int val;

		private InvoiceType(String text, int val) {
			this.text = text;
			this.val = val;
		}

		public String getText() {
			return text;
		}

		public int getVal() {
			return this.val;
		}
	}

	/**
	 * 订单状态枚举类。注意：退货后的退款状态和直接退款状态是合并一起的
	 * 
	 * @ClassName: OrderStatus
	 * @author: 迷蝶
	 * @date: 2018年1月10日 下午3:51:05
	 * 
	 * @Copyright: 2018 <a href="www.itttq.com"
	 *             target="_blank">www.itttq.com</a> Inc. All rights reserved.
	 */
	public static enum OrderStatus {
		/** 待支付，值为1 */
		UNPAID("待支付", 1), /** 待发货，值为2 */
		PAID("待发货", 2), /** 待收货，值为3 */
		SENT("待收货", 3),
		/** 已完成，值为4 */
		COMPLETED("已完成", 4), /** 已取消，值为5 */
		CANCELED("已取消", 5),
		/** 申请退款，值为7 */
		REFUND_APPLY("申请退款", 7), /** 退款中，值为8 */
		REFUNDING("退款中", 8), /** 已退款，值为9 */
		REFUNDED("已退款", 9),
		/** 退款失败，值为10 */
		REFUND_FAIL("退款失败", 10), /** 申请退货，值为11 */
		REFUND_GOODS("申请退货", 11),
		/** 退货中，值为12 */
		REFUNDING_GOODS("退货中", 12), /** 退货失败，值为15 */
		REFUND_GOODS_FAIL("退货失败", 15),
		/** 已删除，只有用户自己删除，值为16 */
		DELETED("已删除", 16),
		/** 取消退款，值为17 */
		CANCEL_REFUND("取消退款", 17),
		/** 取消退货，值为18 */
		CANCEL_REFUND_GOODS("取消退货", 18);
		private String text; // 此处属性不要使用name，会和枚举的name()方法冲突，导致一些问题
		private int val;

		private OrderStatus(String text, int val) {
			this.text = text;
			this.val = val;
		}

		public String getText() {
			return text;
		}

		public int getVal() {
			return this.val;
		}

		/**
		 * 根据文本获取订单状态对象
		 * 
		 * @param text
		 *            文本：UNPAID、PAID等
		 * @Author 迷蝶
		 * @return OrderStatus
		 */
		public static OrderStatus getOrderStatusByName(String name) {
			for (OrderStatus os : OrderStatus.values()) {
				if (os.name().equalsIgnoreCase(name)) {
					return os;
				}
			}
			return null;
		}

		/**
		 * 根据值获取订单状态对象
		 * 
		 * @param val
		 *            枚举值：1、2等
		 * @Author 迷蝶
		 * @return OrderStatus
		 */
		public static OrderStatus getOrderStatusByVal(int val) {
			for (OrderStatus os : OrderStatus.values()) {
				if (os.val == val) {
					return os;
				}
			}
			return null;
		}
	}

	/**
	 * 订单子状态。是由于主状态有多种可能造成，所以用子状态细分。
	 * 
	 * @ClassName: OrderSubStatus
	 * @author: 迷蝶
	 * @date: 2018年1月10日 下午3:57:19
	 * 
	 * @Copyright: 2018 <a href="www.itttq.com"
	 *             target="_blank">www.itttq.com</a> Inc. All rights reserved.
	 */
	public static enum OrderSubStatus {
		/** 用户已取消，值为50 */
		CANCELED_USER("已取消", 50), /** 超时未付款系统取消，值为51 */
		CANCELED_TIMEOUT("未付款取消", 51),
		/** 申请退款，值为70 */
		REFUND_APPLY("申请退款", 70), /** 退货后申请退款，值为71 */
		REFUNDING("退货后退款", 71),
		/** 已退款，值为90 */
		REFUNDED("已退款", 90), /** 退货后已退款，值为91 */
		REFUNDED_GOODS("退货的退款", 91),
		/** 退款失败，值为100 */
		REFUND_FAIL("退款失败", 100), /** 退货后退款失败，值为91 */
		REFUND_FAIL_GOODS("退货的退款失败", 101);
		private String text;
		private int val;

		private OrderSubStatus(String text, int val) {
			this.text = text;
			this.val = val;
		}

		public String getText() {
			return text;
		}

		public int getVal() {
			return this.val;
		}
	}

	/**
	 * 订单操作枚举类。可能多个操作对应一种状态：用户取消、系统取消订单都对应取消订单状态。
	 * 
	 * @ClassName: OrderOperate
	 * @author: 迷蝶
	 * @date: 2018年1月11日 下午10:32:44
	 * @Copyright: 2018 <a href="www.itttq.com"
	 *             target="_blank">www.itttq.com</a> Inc. All rights reserved.
	 */
	public static enum OrderOperate {
		/** 下单，值为1 */
		ORDER("下单", 1), /** 支付，值为2 */
		PAY("支付", 2), /** 发货，值为3 */
		SEND("发货", 3),
		/** 收货，值为4 */
		RECIVE("收货", 4), /** 完成，值为5 */
		COMPLETE("完成", 5), /** 取消，值为6 */
		CANCELE("取消", 6),
		/** 退款，值为7 */
		REFUND("退款", 7), /** 审核，值为8 */
		AUDIT_REFUND("审核", 8), /** 打款，值为9 */
		RIMIT("打款", 9),
		/** 退货，值为10 */
		REFUND_GOODS("退货", 10), /** 审核，值为11 */
		AUDIT_REFUND_GOODS("审核", 11),
		/** 删除，值为12 */
		DELETED("删除", 12),
		/** 取消退款，值为13 */
		CANCEL_REFUND("取消退款", 13), 
		/** 取消退货，值为14 */
		CANCEL_REFUND_GOODS("取消退货", 14);
		private String text;
		private int val;

		private OrderOperate(String text, int val) {
			this.text = text;
			this.val = val;
		}

		public String getText() {
			return text;
		}

		public int getVal() {
			return this.val;
		}

		/**
		 * 根据文本获取订单操作对象
		 * 
		 * @param text
		 *            文本：UNPAID、PAID等
		 * @Author 迷蝶
		 * @return OrderStatus
		 */
		public static OrderOperate getOrderOperateByName(String name) {
			for (OrderOperate oo : OrderOperate.values()) {
				if (oo.name().equalsIgnoreCase(name))
					return oo;
			}
			return null;
		}
	}

	/**
	 * 获取订单编码，规则：来源编码 + 用户ID + 毫秒 + 年月日时分秒 + 6位随机。<br>
	 * 
	 * @param soruce
	 *            来源，见{@link:Source}
	 * @param userId
	 *            用户ID
	 * @Author 迷蝶
	 * @return String
	 */
	public static String getOrderCode(int soruce, int userId) {
		Calendar cal = Calendar.getInstance();
		return soruce + userId + cal.get(Calendar.MILLISECOND) + "_"
				+ cal.get(Calendar.YEAR) + cal.get(Calendar.DATE)
				+ cal.get(Calendar.MINUTE) + cal.get(Calendar.MONTH)
				+ cal.get(Calendar.HOUR_OF_DAY) + cal.get(Calendar.SECOND)
				+ genRandomNum(6);
	}

	/**
	 * 按时间的毫秒级获取文件名称
	 * 
	 * @param pre		文件前缀
	 * @Author 迷蝶
	 * @return String
	 */
	public static String getFilenameByTime(String pre) {
		Calendar cal = Calendar.getInstance();
		return (null == pre ? "" : pre) + cal.get(Calendar.MILLISECOND) + cal.get(Calendar.YEAR)
				+ cal.get(Calendar.DATE) + cal.get(Calendar.MINUTE)
				+ cal.get(Calendar.MONTH) + cal.get(Calendar.HOUR_OF_DAY)
				+ cal.get(Calendar.SECOND);
	}

	/**
	 * 获取随机生成的用户名
	 * 
	 * @param suff
	 *            前缀
	 * @return
	 */
	public static String getUsername(String pre) {
		return pre + genRandomNum(6);
	}

	/**
	 * 获取指定位数的数字，返回为数字的字符串形式，因为可能0在前面，0001这种
	 * 
	 * @param len
	 *            指定长度
	 * @return
	 */
	public static String genRandomNum(int len) {
		char[] str = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
		return getRandom(str, len).toString();
	}

	/**
	 * 获取指定位数的编码，只含数字字母
	 * 
	 * @param len 指定长度
	 * @return
	 */
	public static String genRandomCode(int len) {
		char[] str = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A',
				'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
				'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y',
				'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
				'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
				'x', 'y', 'z'};
		return getRandom(str, len).toString();
	}

	/**
	 * 获取指定位数的编码，含数字字母和简单的符号~!@#$%^&*.?:;
	 * 
	 * @param len 指定长度
	 * @return
	 */
	public static String genRandomChar(int len) {
		char[] str = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A',
				'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
				'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y',
				'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
				'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
				'x', 'y', 'z', ',', '.', '?', ':', ';', '~', '!', '@', '#',
				'$', '%', '^', '&', '*' };
		return getRandom(str, len).toString();
	}

	/**
	 * 根据字符和长度随机获取指定长度的字符
	 * 
	 * @param str
	 * @param len
	 * @return
	 * @Author 迷蝶
	 * @return String
	 */
	public static String getRandom(char[] str, int len) {
		StringBuffer pwd = new StringBuffer("");
		Random r = new Random();
		int i, count = 0; // 生成的密码的长度;
		while (count < len) {
			// 生成随机数，取绝对值，防止生成负数，
			i = Math.abs(r.nextInt(str.length)); // 生成的数最大为36-1
			if (i >= 0 && i < str.length) {
				pwd.append(str[i]);
				count++;
			}
		}
		return pwd.toString();
	}

	/**
	 * 获取真实IP，多级代理后只获取第一个IP
	 * 
	 * @param request
	 * @return
	 * @Author 迷蝶
	 * @return String
	 */
	public static String getIp(HttpServletRequest request) {
		String ip = request.getHeader("x-forwarded-for");

		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknow".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();

			if (ip.equals("127.0.0.1") || ip.equals("0:0:0:0:0:0:0:1")) {
				// 根据网卡获取本机配置的IP地址
				InetAddress inetAddress = null;
				try {
					inetAddress = InetAddress.getLocalHost();
				} catch (UnknownHostException e) {
					e.printStackTrace();
				}
				ip = inetAddress.getHostAddress();
			}
		}

		// 对于通过多个代理的情况，第一个IP为客户端真实的IP地址，多个IP按照','分割
		if (null != ip && ip.length() > 15) {
			// "***.***.***.***".length() = 15
			if (ip.indexOf(",") > 0) {
				ip = ip.substring(0, ip.indexOf(","));
			}
		}
		return ip;
	}

	/**
	 * 对字节数组字符串进行Base64解码并生成图片
	 * 
	 * @param imgStr			图片数据
	 * @param imgFilePath	保存图片全路径地址
	 * @return boolean true表示保存成功，反之为失败，包括图片内容为空
	 */
	public static boolean generateImage(String imgStr, String imgFilePath) {
		if (imgStr == null) return false;
		OutputStream out = null;
		boolean rs = false;
		try {
			// Base64解码
			byte[] b = Base64.decodeBase64(imgStr);
			for (int i = 0; i < b.length; ++i) {
				if (b[i] < 0) {// 调整异常数据
					b[i] += 256;
				}
			}
			// 生成jpeg图片
			File file = new File(imgFilePath);
			out = new FileOutputStream(file);
			out.write(b);
			out.flush();
			rs = true;
		} catch (Exception e) {
			// TODO GXG 异常处理
			e.printStackTrace();
		} finally {
			try {
				if(null != out) out.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return rs;
	}
}
